import { LoadOptions } from '@/ts/base/model';
import { IReception, Reception } from '.';
import { kernel, model, schema } from '../../../../base';
import { NodeType } from '../../../../base/enum';
import { IReceptionProvider } from './IReceptionProvider';
import { ITreeHolder, TreeHolder } from './TreeHolder';
import _ from 'lodash';
import { XForm } from '@/ts/base/schema';
import { is } from '@/ts/base/common/lang/type';
import { ITarget } from '@/ts/core';
import { nextTick } from '@/ts/base/common/timer';

export interface NodeReceptionQuery {
  taskId: string;
  period: string;
  nodeId: string;
}
export interface BelongReceptionQuery {
  taskId: string;
  period: string;
  targetId: string;
  nodeType: NodeType;
}

export interface IReportReception
  extends IReception<model.ReportStatus>,
    IReceptionProvider {
  /** 树形持有 */
  holder: ITreeHolder;
  /** 根据nodeId获取接收信息 */
  getReception(params: NodeReceptionQuery): Promise<IReportReception[]>;
  /** 根据tagetId和nodeType获取接收信息 */
  getReception(params: BelongReceptionQuery): Promise<IReportReception[]>;
  /** 全部汇总 */
  summaryAll(): Promise<Dictionary<Partial<schema.XEntity>>>;
  /** 返回一个查公共集合的`IReceptionProvider` */
  getPublicProvider(): IReceptionProvider;
  /** 属性值穿透 */
  propertySummaryTree(
    attr: schema.XAttribute | model.FieldModel,
    form: XForm,
  ): Promise<model.ReportSummaryTreeNodeView>;
}

export class ReportReception
  extends Reception<model.ReportStatus>
  implements IReportReception
{
  constructor(
    metadata: schema.XReception,
    target: ITarget,
    holder?: ITreeHolder,
    isMySpace = true,
  ) {
    super(metadata, target, isMySpace);
    this.holder = holder ?? new TreeHolder(this.treeId, metadata, this.group.directory);
  }
  holder: ITreeHolder;

  get treeId() {
    return this.data.treeNode.treeId;
  }
  get directoryId() {
    return this.data.directoryId;
  }

  async findReportReceptions(
    nodeIds: string[],
    fromPublic = false,
  ): Promise<Dictionary<schema.XReception | null>> {
    if (this.metadata.content.type != model.TaskContentType.Report) {
      return {};
    }

    const ret: Dictionary<schema.XReception | null> = {};
    const coll = fromPublic
      ? this.publicReceptionColl!
      : this.target.space.resource.receptionColl;

    let res: schema.XReception[] = [];
    const chunks = _.chunk(nodeIds, 5000);
    for (const chunk of chunks) {
      res = res.concat(
        await coll.loadSpace({
          options: {
            match: {
              'content.treeNode.id': {
                _in_: chunk,
              },
              period: this.metadata.period,
              taskId: this.metadata.taskId,
            },
          },
        }),
      );
      await nextTick();
    }
    let ids = [...nodeIds];
    for (const reception of res) {
      const nodeId = (reception.content as model.ReportStatus).treeNode.id;
      ids.splice(ids.indexOf(nodeId), 1);
      ret[nodeId] = reception;
    }
    for (const nodeId of ids) {
      ret[nodeId] = null;
    }
    return ret;
  }

  getPublicProvider(): IReceptionProvider {
    return {
      findReportReceptions: (nodeIds) => {
        return this.findReportReceptions(nodeIds, true);
      },
    };
  }

  async summaryAll(): Promise<Dictionary<Partial<schema.XEntity>>> {
    if (this.data.treeNode.nodeType != NodeType.Summary) {
      throw new Error('当前节点不可汇总');
    }
    const result: Dictionary<Partial<schema.XEntity>> = {};
    await this.holder.loadTree();
    if (this.work && this.holder.tree) {
      const [subTrees] = await this.holder.tree.loadDistributionTree(
        this.data.treeNode,
        this.getPublicProvider(),
        true,
      );
      if (subTrees.length == 0) {
        return result;
      }
      const children = subTrees[0].children;
      const forms = [...this.work.primaryForms, ...this.work.detailForms];
      for (const form of forms) {
        const ids = children.flatMap((item) => {
          return item.reception?.thingId?.[form.id] || [];
        }, 1);

        const loadOptions: LoadOptions<schema.XThing> = {
          options: {
            match: {
              taskId: this.metadata.taskId,
              period: this.period,
              id: {
                _in_: ids,
              },
              isDeleted: false,
            },
          },
        };
        const summaries = await form.loadSummary(loadOptions);

        const item: any = {};
        for (const field of form.summaryFields) {
          item[field.id] = summaries[field.code];
        }
        result[form.id] = item;
      }
    }
    return result;
  }

  async propertySummaryTree(
    attr: schema.XAttribute | model.FieldModel,
    form: XForm,
  ): Promise<model.ReportSummaryTreeNodeView> {
    if (this.data.treeNode.nodeType != NodeType.Summary) {
      throw new Error('当前节点不可汇总');
    }
    let result: model.ReportSummaryTreeNodeView = {
      ...this.data.treeNode,
      children: [],
      value: 0,
    };
    await this.holder.loadTree();
    if (this.work && this.holder.tree) {
      const [subTrees] = await this.holder.tree.loadDistributionTree(
        this.data.treeNode,
        this.getPublicProvider(),
        true,
      );
      if (subTrees.length == 0) {
        return result;
      }

      const children = subTrees[0].children;

      const ids = children.flatMap((item) => {
        return item.reception?.thingId?.[form.id] || [];
      }, 1);

      const loadOptions: LoadOptions<schema.XThing> = {
        options: {
          match: {
            taskId: this.metadata.taskId,
            period: this.period,
            id: {
              _in_: ids,
            },
            isDeleted: false,
          },
        },
      };

      const thingColl = form.collName
        ? this.work.directory.resource.genColl<schema.XThing>(form.collName)
        : this.work.directory.resource.thingColl;
      const list = await thingColl.loadSpace(loadOptions);

      const detailMap = list.reduce<Dictionary<schema.XThing>>((map, row) => {
        map[row.id] = row;
        return map;
      }, {});

      for (const child of children) {
        const childWithValue: model.ReportSummaryTreeNodeView = {
          ...child,
          children: [],
          value: null,
        };
        const id = child.reception?.thingId?.[form.id]?.[0];
        if (id) {
          const data = detailMap[id] || {};
          childWithValue.value = data['T' + attr.propId];
        }
        result.children.push(childWithValue);
      }
      result.value = _.sumBy(result.children, (c) => c.value || 0);
    } else {
      throw new Error('找不到树形');
    }
    return result;
  }

  async getReception(
    params: NodeReceptionQuery | BelongReceptionQuery,
  ): Promise<IReportReception[]> {
    const match: Dictionary<any> = {
      period: params.period,
      taskId: params.taskId,
    };
    if (is<NodeReceptionQuery>(params, !!(params as NodeReceptionQuery).nodeId)) {
      match['content.treeNode.id'] = params.nodeId;
    } else if (params.targetId) {
      match['content.treeNode.targetId'] = params.targetId;
      match['content.treeNode.nodeType'] = params.nodeType || 0;
    } else {
      return [];
    }
    const result = await this.publicReceptionColl?.loadSpace({
      options: {
        match,
      },
    }) || [];
    if (result.length > 0) {
      return result.map((r) => new ReportReception(r, this.target, this.holder));
    }
    return [];
  }
}
